﻿using Microsoft.Extensions.DependencyInjection;

using System;
using System.Reflection;

using zijian666.Core;
using zijian666.Core.Abstractions;
using zijian666.DI.Abstractions;
using zijian666.DI.Features;

namespace zijian666.DI.Defaults;

internal sealed class DefaultAutowiredFeature : IAutowiredFeature
{
    private static Func<IServiceProvider, object>? BuildFactory(ServiceDescriptor serviceDescriptor)
    {
        var serviceType = serviceDescriptor.ServiceType;
        var implementationType = serviceDescriptor.ImplementationType;


        if (serviceDescriptor.ImplementationInstance is var implementationInstance and not null)
        {
            return p => p.Autowired(() => implementationInstance);
        }

        if (serviceDescriptor.ImplementationFactory is var implementationFactory and not null)
        {
            return p => p.Autowired(() => implementationFactory(p));
        }

        return p => p.Autowired(() => ActivatorUtilities.CreateInstance(p, implementationType ?? serviceType));
    }

    /// <summary>
    /// 代理服务描述
    /// </summary>
    public ServiceDescriptor Proxy(ServiceDescriptor service)
    {
        if (CantProxy(service) || IsKeyedService(service))
        {
            return service;
        }

        if (service.ImplementationType is not null)
        {
            if (!AutowiredDescriptor.HasAutowired(service.ImplementationType))
            {
                // 存在服务描述符的实现类型 但是没有自动装配特性, 则不处理服务描述符
                return service;
            }
        }
        else if (service.ImplementationInstance is not null)
        {
            if (!AutowiredDescriptor.HasAutowired(service.ImplementationInstance.GetType()))
            {
                // 存在服务描述符的实例 但是没有自动装配特性, 则不处理服务描述符
                return service;
            }
        }
        else if (service.ServiceType.IsSealed)
        {
            if (!AutowiredDescriptor.HasAutowired(service.ServiceType))
            {
                // 存在服务描述符的服务类型是密封的 但是没有自动装配特性, 则不处理服务描述符
                return service;
            }
        }

        var factory = BuildFactory(service);
        if (factory is not null)
        {
            return new AutowirableServiceDescriptor(service, factory);
        }
        return service;
    }

    /// <summary>
    /// 判断是否为键值服务(兼容带KeyedService版本的Microsoft.Extensions.DependencyInjection)
    /// </summary>
    private static bool IsKeyedService(ServiceDescriptor serviceDescriptor)
    {
        if (serviceDescriptor is null)
        {
            return false;
        }
        var field = serviceDescriptor.GetType().GetProperty("IsKeyedService");
        if (field is null)
        {
            return false;
        }
        return (bool)field.GetValue(serviceDescriptor)!;
    }

    private static bool CantProxy(ServiceDescriptor serviceDescriptor)
    {
        if (serviceDescriptor is AutowirableServiceDescriptor)
        {
            return true;
        }
        if (serviceDescriptor.ServiceType is null)
        {
            return true;
        }
        // 泛型服务无法注入 [Autowired]
        if (serviceDescriptor.ImplementationType is { IsGenericType: true, IsGenericTypeDefinition: true })
        {
            return true;
        }
        return false;
    }

    /// <summary>
    /// 用于代理系统的服务描述，以完成自动装配的动作
    /// </summary>
    private sealed class AutowirableServiceDescriptor(ServiceDescriptor serviceDescriptor, Func<IServiceProvider, object> factory)
        : ServiceDescriptor(serviceDescriptor.ServiceType, factory, serviceDescriptor.Lifetime)
    {

    }

    public int Order { get; } = 0;

    public object? GetService(IAutowiredContext context, AutowiredDescriptor descriptor, Type serviceType)
    {
        if (descriptor.IsKeyedService)
        {
            throw new NotSupportedException("当前环境不支持自动装配键值服务特性, 请先安装 zijian666.DI.Autowired.Net8 或自行实现 IAutowiredFeature 接口");
        }
        return context.GetService(serviceType);
    }
}
